/*
 moxl - Modular XML Library
 Copyright (c) 2007, Malcolm Sparks

 This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License
 as published by the Free Software Foundation; either version 2
 of the License, or (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
package moxl.dom.raw;

import java.util.List;

import org.w3c.dom.Attr;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.NodeList;
import org.w3c.dom.TypeInfo;
import org.w3c.dom.UserDataHandler;

import moxl.dom.MoxlAttribute;
import moxl.dom.MoxlAttributeMap;
import moxl.dom.MoxlElement;
import moxl.dom.MoxlNode;
import moxl.dom.MoxlNodeVisitor;
import moxl.dom.QualifiedName;
import moxl.dom.Visitable;
import moxl.dom.XmlInfosetException;
import moxl.dom.XmlNamespace;
import moxl.dom.XmlNamespaceContext;
import moxl.dom.mutable.MutableElement;
import moxl.dom.support.MoxlAttributeGroup;
import moxl.dom.visitor.support.ElementVisitableSupport;
import moxl.raw.RawAttribute;
import moxl.raw.RawElement;

// Until we fix all these TODOs, which should instruct PMD to ignore so many duplicate TODO strings.
@SuppressWarnings("PMD.AvoidDuplicateLiterals")
public class RawBackedElement implements MutableElement, Visitable
{
	private final RawElement raw;
	private XmlNamespaceContext namespaceContext;

	private final MoxlAttributeGroup attributes = new MoxlAttributeGroup();

	private final RawBackedElementChildren children;

	private final ElementVisitableSupport visitableSupport = ElementVisitableSupport.getInstance();
	private MoxlElement parent;

	public RawBackedElement(RawElement raw)
	{
		this(raw, new XmlNamespaceContext());
	}

	public RawBackedElement(RawElement raw, XmlNamespaceContext parentNamespaceContext)
	{
		this.raw = raw;

		if (parentNamespaceContext == null)
		{
			this.namespaceContext = new XmlNamespaceContext();
		}
		else
		{
			this.namespaceContext = parentNamespaceContext.spawnContext();
		}

		for (RawAttribute attribute : raw.getAttributes())
		{
			String attributeName = attribute.getName();
			if (attributeName.startsWith("xmlns:"))
			{
				int colon = attributeName.indexOf(':');
				String prefix = attributeName.substring(colon + 1);
				XmlNamespace namespace = new XmlNamespace(attribute.getValue());
				namespaceContext.registerNamespace(prefix, namespace);
			}
			else if (attributeName.equals("xmlns"))
			{
				namespaceContext.setNonprefixedNamespace(new XmlNamespace(attribute.getValue()));
			}
		}
		for (RawAttribute rawAttribute : raw.getAttributes())
		{
			String attributeName = rawAttribute.getName();
			if (!attributeName.startsWith("xmlns"))
			{
				MoxlAttribute attribute = new RawBackedAttribute(rawAttribute, namespaceContext);
				attributes.add(attribute);
			}
		}
		children = new RawBackedElementChildren(raw, this, namespaceContext);
	}

	public boolean containsCharacterData()
	{
		return children.containsCharacterData();
	}

	public boolean containsCharacterDataExcludingWhitespace()
	{
		return children.containsCharacterDataExcludingWhitespace();
	}

	public int countChildElements()
	{
		return children.countChildElements();
	}

	public int countChildNodes()
	{
		return children.countChildNodes();
	}

	public MoxlAttribute getAttributeObj(QualifiedName name)
	{
		return attributes.get(name);
	}

	public MoxlAttribute getAttributeObjByString(String name)
	{
		return attributes.get(name);
	}

	public MoxlAttributeMap getAttributeMap()
	{
		return attributes;
	}

	public MoxlElement getChildElement(int index)
	{
		return children.getChildElement(index);
	}

	public MoxlElement getChildElement(QualifiedName name, int index)
	{
		return children.getChildElement(name, index);
	}

	public List<MoxlElement> getChildElements()
	{
		return children.getChildElements();
	}

	public List<MoxlElement> getChildElements(QualifiedName name)
	{
		return children.getChildElements(name);
	}

	public MoxlNode getChildNode(int index)
	{
		return children.getChildNode(index);
	}

	public List<MoxlNode> getChildren()
	{
		return children.getChildNodes();
	}

	public String getContent()
	{
		return children.getContentAsString();
	}

	public XmlNamespace getCurrentNonprefixedNamespace()
	{
		throw new UnsupportedOperationException("TODO");
	}

	public String getLocalName()
	{
		return getName().getLocalPart();
	}

	public QualifiedName getName()
	{
		return namespaceContext.qualifyElementName(raw.getTag());
	}

	public XmlNamespace getNamespace()
	{
		return getName().getNamespace();
	}

	public MoxlElement getRequiredChildElement(QualifiedName name) throws XmlInfosetException
	{
		throw new UnsupportedOperationException("TODO");
	}

	public boolean isEmpty()
	{
		return children.isEmpty();
	}

	public String getNodeName()
	{
		throw new UnsupportedOperationException("TODO");
	}

	public String getStringValue()
	{
		throw new UnsupportedOperationException("TODO");
	}

	public MoxlElement getParent()
	{
		return parent;
	}

	public void addChild(MoxlNode node)
	{
		children.appendChild(node);
	}

	public MoxlNode removeChild(int index)
	{
		MoxlNode result = children.removeChildNode(index);
		result.setParent(null);
		return result;
	}

	public void setParent(MoxlElement parent)
	{
		this.parent = parent;
	}

	public void insertChild(MoxlNode element)
	{
		children.insertChild(element);
	}

	public void accept(MoxlNodeVisitor visitor)
	{
		visitableSupport.accept(visitor, this, children.getChildNodes());
	}

	public XmlNamespaceContext getNamespaceContext()
	{
		return namespaceContext;
	}

	public MoxlElement removeElement(int index)
	{
		return children.removeChildElement(index);
	}

	public void replace(MoxlNode old, MoxlNode replacement)
	{
		children.replace(old, replacement);
	}

	@Override
	public String toString()
	{
		return raw.toString();
	}

	public boolean containsChild(MoxlNode child)
	{
		return children.containsChild(child);
	}

	public void replaceChildWithChildren(MutableElement old)
	{
		List<? extends MoxlNode> list = old.removeChildren();
		replace(old, list);
	}

	public List<MoxlNode> removeChildren()
	{
		return children.removeAll();
	}

	public void replace(MoxlNode old, List<? extends MoxlNode> replacements)
	{
		children.replace(old, replacements);
	}

	public void addChildren(List<? extends MoxlNode> children)
	{
		throw new UnsupportedOperationException("TODO");
	}

	public MoxlElement getFirstChildElement(QualifiedName name)
	{
		return children.getChildElements().get(0);
	}

	public boolean hasAttribute(String name)
	{
		throw new UnsupportedOperationException("TODO");
	}

	public void setAttribute(QualifiedName name, String value)
	{
		throw new UnsupportedOperationException("TODO");
	}

	public void setAttribute(String name, String value)
	{
		throw new UnsupportedOperationException("TODO");
	}

	public String getAttribute(String name)
	{
		throw new UnsupportedOperationException("TODO");
	}

	public String getAttributeNS(String namespaceURI, String localName) throws DOMException
	{
		throw new UnsupportedOperationException("TODO");
	}

	public Attr getAttributeNode(String name)
	{
		throw new UnsupportedOperationException("TODO");
	}

	public Attr getAttributeNodeNS(String namespaceURI, String localName) throws DOMException
	{
		throw new UnsupportedOperationException("TODO");
	}

	public NodeList getElementsByTagName(String name)
	{
		throw new UnsupportedOperationException("TODO");
	}

	public NodeList getElementsByTagNameNS(String namespaceURI, String localName) throws DOMException
	{
		throw new UnsupportedOperationException("TODO");
	}

	public TypeInfo getSchemaTypeInfo()
	{
		throw new UnsupportedOperationException("TODO");
	}

	public String getTagName()
	{
		throw new UnsupportedOperationException("TODO");
	}

	public boolean hasAttributeNS(String namespaceURI, String localName) throws DOMException
	{
		throw new UnsupportedOperationException("TODO");
	}

	public void removeAttribute(String name) throws DOMException
	{
		throw new UnsupportedOperationException("TODO");
	}

	public void removeAttributeNS(String namespaceURI, String localName) throws DOMException
	{
		throw new UnsupportedOperationException("TODO");
	}

	public Attr removeAttributeNode(Attr oldAttr) throws DOMException
	{
		throw new UnsupportedOperationException("TODO");
	}

	public void setAttributeNS(String namespaceURI, String qualifiedName, String value) throws DOMException
	{
		throw new UnsupportedOperationException("TODO");
	}

	public Attr setAttributeNode(Attr newAttr) throws DOMException
	{
		throw new UnsupportedOperationException("TODO");
	}

	public Attr setAttributeNodeNS(Attr newAttr) throws DOMException
	{
		throw new UnsupportedOperationException("TODO");
	}

	public void setIdAttribute(String name, boolean isId) throws DOMException
	{
		throw new UnsupportedOperationException("TODO");
	}

	public void setIdAttributeNS(String namespaceURI, String localName, boolean isId) throws DOMException
	{
		throw new UnsupportedOperationException("TODO");
	}

	public void setIdAttributeNode(Attr idAttr, boolean isId) throws DOMException
	{
		throw new UnsupportedOperationException("TODO");
	}

	public org.w3c.dom.Node appendChild(org.w3c.dom.Node newChild) throws DOMException
	{
		throw new UnsupportedOperationException("TODO");
	}

	public org.w3c.dom.Node cloneNode(boolean deep)
	{
		throw new UnsupportedOperationException("TODO");
	}

	public short compareDocumentPosition(org.w3c.dom.Node other) throws DOMException
	{
		throw new UnsupportedOperationException("TODO");
	}

	public NamedNodeMap getAttributes()
	{
		throw new UnsupportedOperationException("TODO");
	}

	public String getBaseURI()
	{
		throw new UnsupportedOperationException("TODO");
	}

	public NodeList getChildNodes()
	{
		throw new UnsupportedOperationException("TODO");
	}

	public Object getFeature(String feature, String version)
	{
		throw new UnsupportedOperationException("TODO");
	}

	public org.w3c.dom.Node getFirstChild()
	{
		throw new UnsupportedOperationException("TODO");
	}

	public org.w3c.dom.Node getLastChild()
	{
		throw new UnsupportedOperationException("TODO");
	}

	public String getNamespaceURI()
	{
		throw new UnsupportedOperationException("TODO");
	}

	public org.w3c.dom.Node getNextSibling()
	{
		throw new UnsupportedOperationException("TODO");
	}

	public short getNodeType()
	{
		throw new UnsupportedOperationException("TODO");
	}

	public String getNodeValue() throws DOMException
	{
		throw new UnsupportedOperationException("TODO");
	}

	public Document getOwnerDocument()
	{
		throw new UnsupportedOperationException("TODO");
	}

	public org.w3c.dom.Node getParentNode()
	{
		throw new UnsupportedOperationException("TODO");
	}

	public String getPrefix()
	{
		throw new UnsupportedOperationException("TODO");
	}

	public org.w3c.dom.Node getPreviousSibling()
	{
		throw new UnsupportedOperationException("TODO");
	}

	public String getTextContent() throws DOMException
	{
		throw new UnsupportedOperationException("TODO");
	}

	public Object getUserData(String key)
	{
		throw new UnsupportedOperationException("TODO");
	}

	public boolean hasAttributes()
	{
		throw new UnsupportedOperationException("TODO");
	}

	public boolean hasChildNodes()
	{
		throw new UnsupportedOperationException("TODO");
	}

	public org.w3c.dom.Node insertBefore(org.w3c.dom.Node newChild, org.w3c.dom.Node refChild) throws DOMException
	{
		throw new UnsupportedOperationException("TODO");
	}

	public boolean isDefaultNamespace(String namespaceURI)
	{
		throw new UnsupportedOperationException("TODO");
	}

	public boolean isEqualNode(org.w3c.dom.Node arg)
	{
		throw new UnsupportedOperationException("TODO");
	}

	public boolean isSameNode(org.w3c.dom.Node other)
	{
		throw new UnsupportedOperationException("TODO");
	}

	public boolean isSupported(String feature, String version)
	{
		throw new UnsupportedOperationException("TODO");
	}

	public String lookupNamespaceURI(String prefix)
	{
		throw new UnsupportedOperationException("TODO");
	}

	public String lookupPrefix(String namespaceURI)
	{
		throw new UnsupportedOperationException("TODO");
	}

	public void normalize()
	{
		throw new UnsupportedOperationException("TODO");
	}

	public org.w3c.dom.Node removeChild(org.w3c.dom.Node oldChild) throws DOMException
	{
		throw new UnsupportedOperationException("TODO");
	}

	public org.w3c.dom.Node replaceChild(org.w3c.dom.Node newChild, org.w3c.dom.Node oldChild) throws DOMException
	{
		throw new UnsupportedOperationException("TODO");
	}

	public void setNodeValue(String nodeValue) throws DOMException
	{
		throw new UnsupportedOperationException("TODO");
	}

	public void setPrefix(String prefix) throws DOMException
	{
		throw new UnsupportedOperationException("TODO");
	}

	public void setTextContent(String textContent) throws DOMException
	{
		throw new UnsupportedOperationException("TODO");
	}

	public Object setUserData(String key, Object data, UserDataHandler handler)
	{
		throw new UnsupportedOperationException("TODO");
	}

	public List<MoxlElement> getChildElements(String name)
    {
	    throw new UnsupportedOperationException("TODO");
    }

	public MoxlElement getFirstChildElement(String name)
    {
	    throw new UnsupportedOperationException("TODO");
    }

}
